package com.vue.service.impl;

import cn.hutool.http.*;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.vue.bean.R;
import com.vue.entity.UserEntity;
import com.vue.service.IWeChatService;
import com.vue.service.UserService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;

/**
 * 微信小程序登录
 *
 * @author: wrj
 * @since: 2024/9/27 17:08
 * @description:
 */

@Slf4j
@Service
@AllArgsConstructor
public class WeChatServiceImpl implements IWeChatService {

    private static final String APP_ID = "wxde77d7bbea8db745";

    private static final String SECRET = "eeef28d59b5283cf16b66a68fc49f9e1";

    private static final String GRANT_TYPE = "client_credential";

    private static final String BASE_URL = "https://api.weixin.qq.com";

    private final UserService userService;
    /**
     * 微信小程序通过手机号登录
     * @param code null
     * @return R
     * @author wrj
     * @since 2024/9/29 下午3:48
     */
    @Override
    public R login(String code) throws Exception {
        // 1.获取oppenid(未认证的小程序只能用这个，这是wx.lonin生成code和根据手机号的方式不是一个code码)
        String openId = getOpenid(code);
//            // 2.获取手机号凭证
//            String accessToken = getAccessToken();
//            // 3.获取手机号
//            String phone = getPhone(code, accessToken);
        // 4.根据openid查询数据库  如果有的话就修改手机号， 没有就新增
        UserEntity user = userService.getBaseMapper().selectOne(new QueryWrapper<UserEntity>().lambda().eq(UserEntity::getOpenId, openId));
        if (user == null) {
            UserEntity po = new UserEntity();
            po.setOpenId(openId);
            po.setPassword("123456");
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMddHHmmss");
            po.setName(LocalDateTime.now().format(formatter));
            po.setRealName("游客");
            userService.save(po);
            return R.data(po);
        }
        // 5.登录成功设置令牌(暂不使用)
//            Map<String, Object> clams = new HashMap<>();
//            clams.put("id", member.getId());
//            clams.put("name", member.getNickname());
//            String token = JwtUtils.generateToken(SECRET, 24, clams);
//            members.setToken(token);
        return R.data(user);
    }

    /**
     * 根据code获取用户在小程序的唯一标识
     *
     * @param code
     * @return
     */
    private String getOpenid(String code) throws Exception{
        String url = "/sns/jscode2session";
        Map<String, Object> params = new HashMap<>();
        params.put("appid", APP_ID);
        params.put("secret", SECRET);
        params.put("js_code", code);
        params.put("grant_type", GRANT_TYPE);
        JSONObject resObj = null;
        Object errcode = null;
        try {
            HttpRequest request = HttpUtil.createRequest(Method.POST, BASE_URL + url).form(params);
            HttpResponse response = request.execute();
            resObj = JSONObject.parseObject(response.body());
            log.info("根据code:code获取用户在小程序的唯一标识:{}", JSON.toJSON(resObj));
            errcode = resObj.get("errcode");
        } catch (HttpException e) {
            throw new Exception("系统异常");
        }
        log.info("resObj: {}", resObj);
        if (errcode != null) {
            throw new Exception("获取appId错误");
        }
        return (String) resObj.get("openid");
    }

    /**
     * 获取手机号令牌token
     * @return
     */
    private String getAccessToken() throws Exception{
        String url = "/cgi-bin/token";
        Map<String, Object> params = new HashMap<>();
        params.put("grant_type", GRANT_TYPE);
        params.put("appid", APP_ID);
        params.put("secret", SECRET);
        String token = null;
        try {
            String resStr = HttpUtil.get(BASE_URL + url, params);
            token = (String) JSONUtil.parseObj(resStr).get("access_token");
        } catch (Exception e) {
            throw new Exception("获取token异常");
        }
        return token;
    }

    /**
     * 获取手机号
     * @param phoneCode    手机号获取凭证（前端登录传入的）
     * @param accessToken 手机号接口调用凭证
     * @return
     */
    private String getPhone(String phoneCode, String accessToken) throws Exception{
        String url = "/wxa/business/getuserphonenumber";
        Map<String, Object> bodys = new HashMap<>();
        bodys.put("code", phoneCode);
        String phone = null;
        try {
            HttpRequest request = HttpUtil.createRequest(Method.POST, BASE_URL + url+"?access_token="+accessToken);
            request.body(JSONUtil.toJsonStr(bodys));
            HttpResponse response = request.execute();
            String resStr =response.body();
            log.info("获取手机号相关信息：{}", resStr);
            Object phoneInfo = JSONUtil.parseObj(resStr). get("phone_info");
            phone = JSONUtil.parseObj(phoneInfo).getStr("phoneNumber");
            if (ObjectUtils.isEmpty(phone)){
                throw new Exception("获取手机号失败");
            }
            return phone;
        } catch (Exception e) {
            throw new Exception("获取手机号失败");
        }
    }
}
